<template>

  <a-select
    show-arrow
    :value="showValue"
    :mode="mode"
    :max-tag-count="maxTagCount"
    style="minWidth: 130px"
    :placeholder="placeholder"
    allow-clear
    :show-search="showSearch"
    @change="chanegValueHandler"
    @search="searchValuesHandler"
    @focus="focusHandler"
  >
    <a-icon slot="suffixIcon" :component="require('@/assets/icon/arrow-down-bold.svg')" />
    <div slot="dropdownRender">
      <RecycleScroller
        v-if="flist.length > 0"
        class="virtual-selector__scroller virtual-selector__dropdown"
        :items="flist"
        :item-size="itemSize"
        :key-field="option.itemNameKey"
      >

        <div slot-scope="{ item }">

          <a-tooltip placement="left" :destroy-tooltip-on-hide="true" :mouse-enter-delay="0.2">
            <template v-if="tooltip" slot="title">
              <span>{{ item[option.itemNameKey] }}</span>
            </template>
            <div
              class="virtual-selector__dropdown-item"
              :class="{
                'virtual-selector__dropdown-item--selected':
                  value.includes(item[option.itemNameKey])||value.includes(item[option.itemValueKey]),
              }"
              @mousedown="handleMousedown"
              @click="handleItemSelect($event, item)"
            >

              <div class="vs-item-text">
                {{ item[option.itemNameKey] }}
                <span v-if="showNum">({{ item['num'] }})</span>
              </div>

              <span
                class="vs-item-active"
                :class="{
                  'vs-item-selected':
                    value.includes(item[option.itemNameKey]),
                }"
              ><a-icon type="check" /></span>
            </div>
          </a-tooltip>
        </div>

      </RecycleScroller>
      <div v-else class="c-empty-box">
        暂无数据
      </div>
    </div>
  </a-select>
</template>

<script>
import { RecycleScroller } from 'vue-virtual-scroller';
import 'vue-virtual-scroller/dist/vue-virtual-scroller.css';
import { debounce } from '@/utils/util';
const defaultItemGap = 0;

export default {
  name: 'VirtualSelector',
  components: { RecycleScroller },

  props: {
    loading: {
      type: Boolean,
      default: false
    },
    label: {
      type: String,
      default: ''
    },
    placeholder: {
      type: String,
      default: ''
    },
    showNum: {
      type: Boolean,
      default: false
    },
    value: {
      type: [Array, String],
      default: () => []
    },
    list: {
      type: Array,
      required: true,
      default: () => []
    },
    tooltip: {
      type: Boolean,
      default: false
    },
    mode: {
      type: String,
      default: 'default'
    },
    showSearch: {
      type: Boolean,
      default: false
    },
    maxTagCount: {
      type: Number,
      default: 1
    },
    /**
     * option: {
     *   itemNameKey: string,
     *   itemValueKey: string,
     *   itemPageSize: number
     *   itemGap: number
     * }
     */
    option: {
      type: Object,
      required: true,
      default: () => {}
    }
  },
  data() {
    return {
      id: new Date().getTime(),
      flist: [],
      selected: {},
      showValue: [],
      itemSize: 32 + ((this.option && this.option.itemGap) || defaultItemGap)
    };
  },
  watch: {
    list: {
      immediate: true,
      handler() {
        this.init();
      }
    }
  },
  methods: {
    init() {
      if (
        !this.option ||
        !this.option.itemNameKey ||
        !this.option.itemValueKey
      ) {
        throw new Error(
          'Please specify list option "itemNameKey" or "itemValueKey"'
        );
      }
      this.flist = [...this.list];
    },
    searchValuesHandler: debounce(function(v) {
      if (!v || v.length === 0) {
        this.flist = [...this.list];
      } else {
        this.flist = this.list.filter((item) => {
          if (item[this.option.itemNameKey]?.toLowerCase() === v.toLowerCase()) {
            this.$emit('changeValueHandler', [item[this.option.itemNameKey]]);
          }

          return item[this.option.itemNameKey]?.toString()
            .toLowerCase()
            .includes(v.toLowerCase()) ?? '';
        });
      }
    }, 500),

    chanegValueHandler(v) {
      if (this.mode === 'default') {
        if (v === '') {
          this.searchValuesHandler(v);
        }
        this.$emit('changeValueHandler', v);
        this.showValue = v;
      } else {
        if (v.length === 0) {
          this.searchValuesHandler('');
        }
        this.$emit('changeValueHandler', [...v]);
        this.showValue = [...v];
      }
    },
    handleMousedown(e) {
      if (this.mode !== 'default') {
        e.preventDefault();
      }
    },
    focusHandler() {
      this.flist = [...this.list];
    },
    handleItemSelect(e, item) {
      const text = item[this.option.itemNameKey];
      const value = item[this.option.itemValueKey];
      if (this.mode === 'default') {
        this.$emit('changeValueHandler', value);
        this.showValue = text;
      } else {
        const textIndex = this.showValue.indexOf(text);

        if (textIndex === -1) {
          this.$emit('changeValueHandler', [...this.value, value]);
          this.showValue = [...this.showValue, text];
        } else {
          const v1 = [...this.value];
          const v2 = [...this.showValue];
          v1.splice(textIndex, 1);
          v2.splice(textIndex, 1);
          this.showValue = v2;
          this.$emit('changeValueHandler', [...v1]);
        }
      }
    }
  }
};
</script>

<style lang="less" scoped>
@import 'index.less';
</style>

